shooter: Use the reftests code for taking screenshots
authorJasper St. Pierre <jstpierre@mecheye.net>
Wed, 17 Jul 2013 20:54:42 +0000 (16:54 -0400)
committerJasper St. Pierre <jstpierre@mecheye.net>
Wed, 17 Jul 2013 20:57:55 +0000 (16:57 -0400)
docs/tools/Makefile.am
docs/tools/shadow.c [deleted file]
docs/tools/shadow.h [deleted file]
docs/tools/shooter.c

index e3b2966bada0ee80c8779b11d5dc3e318af31cb9..80ddcf2114870ced7c4fb131b6e4893e7d37bdf6 100644 (file)
@@ -26,8 +26,6 @@ endif
 doc_shooter_DEPENDENCIES = $(DEPS)
 doc_shooter_LDADD = $(LDADDS)
 doc_shooter_SOURCES=   \
-       shadow.c        \
-       shadow.h        \
        shooter.c       \
        widgets.c       \
        widgets.h
diff --git a/docs/tools/shadow.c b/docs/tools/shadow.c
deleted file mode 100644 (file)
index 67c31fe..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-#include "shadow.h"
-#include <math.h>
-
-#define BLUR_RADIUS 5
-#define SHADOW_OFFSET (BLUR_RADIUS * 4 / 5)
-#define SHADOW_OPACITY 0.75
-
-typedef struct {
-  int size;
-  double *data;
-} ConvFilter;
-
-static double
-gaussian (double x, double y, double r)
-{
-    return ((1 / (2 * M_PI * r)) *
-           exp ((- (x * x + y * y)) / (2 * r * r)));
-}
-
-static ConvFilter *
-create_blur_filter (int radius)
-{
-  ConvFilter *filter;
-  int x, y;
-  double sum;
-  
-  filter = g_new0 (ConvFilter, 1);
-  filter->size = radius * 2 + 1;
-  filter->data = g_new (double, filter->size * filter->size);
-
-  sum = 0.0;
-  
-  for (y = 0 ; y < filter->size; y++)
-    {
-      for (x = 0 ; x < filter->size; x++)
-       {
-         sum += filter->data[y * filter->size + x] = gaussian (x - (filter->size >> 1),
-                                                               y - (filter->size >> 1),
-                                                               radius);
-       }
-    }
-
-  for (y = 0; y < filter->size; y++)
-    {
-      for (x = 0; x < filter->size; x++)
-       {
-         filter->data[y * filter->size + x] /= sum;
-       }
-    }
-
-  return filter;
-  
-}
-
-static GdkPixbuf *
-create_shadow (GdkPixbuf *src)
-{
-  int x, y, i, j;
-  int width, height;
-  GdkPixbuf *dest;
-  static ConvFilter *filter = NULL;
-  int src_rowstride, dest_rowstride;
-  int src_bpp, dest_bpp;
-  
-  guchar *src_pixels, *dest_pixels;
-
-  if (!filter)
-    filter = create_blur_filter (BLUR_RADIUS);
-  
-  width = gdk_pixbuf_get_width (src) + BLUR_RADIUS * 2 + SHADOW_OFFSET;
-  height = gdk_pixbuf_get_height (src) + BLUR_RADIUS * 2 + SHADOW_OFFSET;
-
-  dest = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (src),
-                        gdk_pixbuf_get_has_alpha (src),
-                        gdk_pixbuf_get_bits_per_sample (src),
-                        width, height);
-  gdk_pixbuf_fill (dest, 0);  
-  src_pixels = gdk_pixbuf_get_pixels (src);
-  src_rowstride = gdk_pixbuf_get_rowstride (src);
-  src_bpp = gdk_pixbuf_get_has_alpha (src) ? 4 : 3;
-  
-  dest_pixels = gdk_pixbuf_get_pixels (dest);
-  dest_rowstride = gdk_pixbuf_get_rowstride (dest);
-  dest_bpp = gdk_pixbuf_get_has_alpha (dest) ? 4 : 3;
-  
-  for (y = 0; y < height; y++)
-    {
-      for (x = 0; x < width; x++)
-       {
-         int sumr = 0, sumg = 0, sumb = 0, suma = 0;
-
-         for (i = 0; i < filter->size; i++)
-           {
-             for (j = 0; j < filter->size; j++)
-               {
-                 int src_x, src_y;
-
-                 src_y = -(BLUR_RADIUS + SHADOW_OFFSET) + y - (filter->size >> 1) + i;
-                 src_x = -(BLUR_RADIUS + SHADOW_OFFSET) + x - (filter->size >> 1) + j;
-
-                 if (src_y < 0 || src_y > gdk_pixbuf_get_height (src) ||
-                     src_x < 0 || src_x > gdk_pixbuf_get_width (src))
-                   continue;
-
-                 sumr += src_pixels [src_y * src_rowstride +
-                                     src_x * src_bpp + 0] *
-                   filter->data [i * filter->size + j];
-                 sumg += src_pixels [src_y * src_rowstride +
-                                     src_x * src_bpp + 1] * 
-                   filter->data [i * filter->size + j];
-
-                 sumb += src_pixels [src_y * src_rowstride +
-                                     src_x * src_bpp + 2] * 
-                   filter->data [i * filter->size + j];
-                 
-                 if (src_bpp == 4)
-                   suma += src_pixels [src_y * src_rowstride +
-                                       src_x * src_bpp + 3] *
-                   filter->data [i * filter->size + j];
-
-                   
-               }
-           }
-
-         if (dest_bpp == 4)
-           dest_pixels [y * dest_rowstride +
-                        x * dest_bpp + 3] = suma * SHADOW_OPACITY;
-
-       }
-    }
-  
-  return dest;
-}
-
-GdkPixbuf *
-create_shadowed_pixbuf (GdkPixbuf *src)
-{
-  GdkPixbuf *dest;
-  
-  dest = create_shadow (src);
-
-  gdk_pixbuf_composite (src, dest,
-                       BLUR_RADIUS, BLUR_RADIUS,
-                       gdk_pixbuf_get_width (src),
-                       gdk_pixbuf_get_height (src),
-                       BLUR_RADIUS, BLUR_RADIUS, 1.0, 1.0,
-                       GDK_INTERP_NEAREST, 255);
-  return dest;
-}
diff --git a/docs/tools/shadow.h b/docs/tools/shadow.h
deleted file mode 100644 (file)
index 2f569cc..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef __SHADOW_H__
-#define __SHADOW_H__
-
-#include <gdk-pixbuf/gdk-pixbuf.h>
-
-GdkPixbuf *create_shadowed_pixbuf (GdkPixbuf *src);
-
-#endif /* __SHADOW_H__ */
index 1d3eeb26df664432eb3cbe08f4b29b6b67531e42..84c993e25cbd30631bb5856a4b4888d3a5602d25 100644 (file)
-#include <gdk/gdk.h>
+
 #include <gtk/gtk.h>
-#include <gdkx.h>
-#include <stdio.h>
-#include <errno.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <X11/extensions/shape.h>
-
-#include <gdk-pixbuf/gdk-pixbuf.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <signal.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <locale.h>
 #include "widgets.h"
-#include "shadow.h"
-
-#define MAXIMUM_WM_REPARENTING_DEPTH 4
-#ifndef _
-#define _(x) (x)
-#endif
-
-static Window
-find_toplevel_window (Window xid)
-{
-  Window root, parent, *children;
-  guint nchildren;
-
-  do
-    {
-      if (XQueryTree (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), xid, &root,
-                     &parent, &children, &nchildren) == 0)
-       {
-         g_warning ("Couldn't find window manager window");
-         return 0;
-       }
-
-      if (root == parent)
-       return xid;
 
-      xid = parent;
-    }
-  while (TRUE);
-}
+typedef enum {
+  SNAPSHOT_WINDOW,
+  SNAPSHOT_DRAW
+} SnapshotMode;
 
-static GdkPixbuf *
-add_border_to_shot (GdkPixbuf *pixbuf)
+static gboolean
+quit_when_idle (gpointer loop)
 {
-  GdkPixbuf *retval;
-
-  retval = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
-                          gdk_pixbuf_get_width (pixbuf) + 2,
-                          gdk_pixbuf_get_height (pixbuf) + 2);
-
-  /* Fill with solid black */
-  gdk_pixbuf_fill (retval, 0xFF);
-  gdk_pixbuf_copy_area (pixbuf,
-                       0, 0,
-                       gdk_pixbuf_get_width (pixbuf),
-                       gdk_pixbuf_get_height (pixbuf),
-                       retval, 1, 1);
+  g_main_loop_quit (loop);
 
-  return retval;
+  return G_SOURCE_REMOVE;
 }
 
-static GdkPixbuf *
-remove_shaped_area (GdkPixbuf *pixbuf,
-                   Window     window)
+static void
+check_for_draw (GdkEvent *event, gpointer loop)
 {
-  GdkPixbuf *retval;
-  XRectangle *rectangles;
-  int rectangle_count, rectangle_order;
-  int i;
-
-  retval = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8,
-                          gdk_pixbuf_get_width (pixbuf),
-                          gdk_pixbuf_get_height (pixbuf));
-  
-  gdk_pixbuf_fill (retval, 0);
-  rectangles = XShapeGetRectangles (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), window,
-                                   ShapeBounding, &rectangle_count, &rectangle_order);
-
-  for (i = 0; i < rectangle_count; i++)
+  if (event->type == GDK_EXPOSE)
     {
-      int y, x;
-
-      for (y = rectangles[i].y; y < rectangles[i].y + rectangles[i].height; y++)
-       {
-         guchar *src_pixels, *dest_pixels;
-
-         src_pixels = gdk_pixbuf_get_pixels (pixbuf) +
-           y * gdk_pixbuf_get_rowstride (pixbuf) +
-           rectangles[i].x * (gdk_pixbuf_get_has_alpha (pixbuf) ? 4 : 3);
-         dest_pixels = gdk_pixbuf_get_pixels (retval) +
-           y * gdk_pixbuf_get_rowstride (retval) +
-           rectangles[i].x * 4;
-
-         for (x = rectangles[i].x; x < rectangles[i].x + rectangles[i].width; x++)
-           {
-             *dest_pixels++ = *src_pixels ++;
-             *dest_pixels++ = *src_pixels ++;
-             *dest_pixels++ = *src_pixels ++;
-             *dest_pixels++ = 255;
-
-             if (gdk_pixbuf_get_has_alpha (pixbuf))
-               src_pixels++;
-           }
-       }
+      g_idle_add (quit_when_idle, loop);
+      gdk_event_handler_set ((GdkEventFunc) gtk_main_do_event, NULL, NULL);
     }
 
-  return retval;
+  gtk_main_do_event (event);
 }
 
-static GdkPixbuf *
-take_window_shot (Window   child,
-                 gboolean include_decoration)
+static cairo_surface_t *
+snapshot_widget (GtkWidget *widget, SnapshotMode mode)
 {
-  GdkWindow *window;
-  Window xid;
-  gint x_orig, y_orig;
-  gint x = 0, y = 0;
-  gint width, height;
-
-  GdkPixbuf *tmp, *tmp2;
-  GdkPixbuf *retval;
-
-  if (include_decoration)
-    xid = find_toplevel_window (child);
-  else
-    xid = child;
-
-  window = gdk_x11_window_foreign_new_for_display (gdk_display_get_default (), xid);
-
-  width = gdk_window_get_width (window);
-  height = gdk_window_get_height (window);
-  gdk_window_get_origin (window, &x_orig, &y_orig);
-
-  if (x_orig < 0)
+  cairo_surface_t *surface;
+  cairo_pattern_t *bg;
+  GMainLoop *loop;
+  cairo_t *cr;
+
+  g_assert (gtk_widget_get_realized (widget));
+
+  surface = gdk_window_create_similar_surface (gtk_widget_get_window (widget),
+                                               CAIRO_CONTENT_COLOR,
+                                               gtk_widget_get_allocated_width (widget),
+                                               gtk_widget_get_allocated_height (widget));
+
+  loop = g_main_loop_new (NULL, FALSE);
+  /* We wait until the widget is drawn for the first time.
+   * We can not wait for a GtkWidget::draw event, because that might not
+   * happen if the window is fully obscured by windowed child widgets.
+   * Alternatively, we could wait for an expose event on widget's window.
+   * Both of these are rather hairy, not sure what's best. */
+  gdk_event_handler_set (check_for_draw, loop, NULL);
+  g_main_loop_run (loop);
+
+  cr = cairo_create (surface);
+
+  switch (mode)
     {
-      x = - x_orig;
-      width = width + x_orig;
-      x_orig = 0;
+    case SNAPSHOT_WINDOW:
+      {
+        GdkWindow *window = gtk_widget_get_window (widget);
+        if (gdk_window_get_window_type (window) == GDK_WINDOW_TOPLEVEL ||
+            gdk_window_get_window_type (window) == GDK_WINDOW_FOREIGN)
+          {
+            /* give the WM/server some time to sync. They need it.
+             * Also, do use popups instead of toplevls in your tests
+             * whenever you can. */
+            gdk_display_sync (gdk_window_get_display (window));
+            g_timeout_add (500, quit_when_idle, loop);
+            g_main_loop_run (loop);
+          }
+        gdk_cairo_set_source_window (cr, window, 0, 0);
+        cairo_paint (cr);
+      }
+      break;
+    case SNAPSHOT_DRAW:
+      bg = gdk_window_get_background_pattern (gtk_widget_get_window (widget));
+      if (bg)
+        {
+          cairo_set_source (cr, bg);
+          cairo_paint (cr);
+        }
+      gtk_widget_draw (widget, cr);
+      break;
+    default:
+      g_assert_not_reached();
+      break;
     }
 
-  if (y_orig < 0)
-    {
-      y = - y_orig;
-      height = height + y_orig;
-      y_orig = 0;
-    }
-
-  if (x_orig + width > gdk_screen_width ())
-    width = gdk_screen_width () - x_orig;
-
-  if (y_orig + height > gdk_screen_height ())
-    height = gdk_screen_height () - y_orig;
-
-  tmp = gdk_pixbuf_get_from_window (window,
-                                   x, y, width, height);
+  cairo_destroy (cr);
+  g_main_loop_unref (loop);
+  gtk_widget_destroy (widget);
 
-  if (include_decoration)
-    tmp2 = remove_shaped_area (tmp, xid);
-  else
-    tmp2 = add_border_to_shot (tmp);
-
-  retval = create_shadowed_pixbuf (tmp2);
-  g_object_unref (tmp);
-  g_object_unref (tmp2);
-
-  return retval;
+  return surface;
 }
 
 int main (int argc, char **argv)
 {
   GList *toplevels;
-  GdkPixbuf *screenshot = NULL;
   GList *node;
 
   /* If there's no DISPLAY, we silently error out.  We don't want to break
@@ -190,42 +107,19 @@ int main (int argc, char **argv)
 
   for (node = toplevels; node; node = g_list_next (node))
     {
-      GtkAllocation allocation;
-      GdkWindow *window;
       WidgetInfo *info;
-      XID id;
       char *filename;
+      cairo_surface_t *surface;
 
       info = node->data;
 
       gtk_widget_show (info->window);
 
-      window = gtk_widget_get_window (info->window);
-      gtk_widget_get_allocation (info->window, &allocation);
-
-      gtk_widget_show_now (info->window);
-      gtk_widget_queue_draw_area (info->window,
-                                  allocation.x, allocation.y,
-                                  allocation.width, allocation.height);
-      gdk_window_process_updates (window, TRUE);
-
-      while (gtk_events_pending ())
-       {
-         gtk_main_iteration ();
-       }
-      sleep (1);
-
-      while (gtk_events_pending ())
-       {
-         gtk_main_iteration ();
-       }
-
-      id = gdk_x11_window_get_xid (window);
-      screenshot = take_window_shot (id, info->include_decorations);
+      surface = snapshot_widget (info->window,
+                                 info->include_decorations ? SNAPSHOT_WINDOW : SNAPSHOT_DRAW);
       filename = g_strdup_printf ("./%s.png", info->name);
-      gdk_pixbuf_save (screenshot, filename, "png", NULL, NULL);
-      g_free(filename);
-      gtk_widget_hide (info->window);
+      g_assert (cairo_surface_write_to_png (surface, filename) == CAIRO_STATUS_SUCCESS);
+      g_free (filename);
     }
 
   return 0;